//
// CPE301 DA5
//  Justin Swinney
//  1. Write a C AVR program that will monitor the LM34 connected to an Analog pin to
// display the temperature in F on the serial terminal every 1 sec. Use a timer with
// interrupt for the 1 sec delay.
// 
// 2. Write a C AVR program that will monitor the LM34 connected to an Analog pin to
// display the temperature in F on 7-seg displays given.
// 

#define F_OSC 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//Variables
unsigned char temp_high; // variable to hold high temperature value
unsigned char temp_low; // variable to hold low temperature value
int time = 0; // temp-time

//timer 1 initialization
void timer1_init(int value)
{
	TCCR1A = 0x00;
	TCCR1B = 0x05;
	TCNT1H = 0xF9;
	TCNT1L = 0xE5;
	if(value)
		TIFR1 = 0x01; //clears TOV1
}

//USART initialization
void usart_init (int dir)
{
	DDRB = 0x03; //USART output pins
	UCSR0C = 0x06; //8 bit, 1 stop bit, rising edge, asynchronous
	if(dir)
		UCSR0B = 0x08; //transmit
	else
		UCSR0B = 0x10; //receive	
	UBRR0H = 0x00; //settings for usart, 9600 baud rate
	UBRR0L = 0x33;
}

//USART sending function
void usart_send (unsigned char ch, int ivalue)
{
	while(!(UCSR0A & (1<<UDRE0)));
	if(ivalue) //we can have either an integer value or character
		UDR0 = ch+48; //if integer, add 48 to convert to ASCII
	else
		UDR0 = ch; //otherwise send character
}

//adc setup
void ADC_init()
{	
	ADCSRA = 0xDF; //128 prescaler
	ADCSRB = 0x06; //timer1 overflow
	ADMUX = 0xC0; //ADC0, AREF
}

//spi_setup
void execute(unsigned char cmd, unsigned char data)
{
	PORTB &= ~(1<<3);					// initializing the packet by pulling SS low
	SPDR = cmd;							// start CMD transmission
	while (!(SPSR & (1<<SPIF)));        // wait transfer finish
	
	SPDR = data;						// start DATA transmission
	while (!(SPSR & (1<<SPIF)));        //    wait transfer finish
	
	PORTB |= (1<<3);					// terminate the packet by pulling SS high
}

//initialize seven segment
void setup_7seg()
{
		DDRB = 0x83;// given pins set as output
		SPCR = 0x23; // set up spi
   
        execute(0x09,0x03);  // enable coding of digits 1,2
        execute(0x0A,0x0F);	// Max intensity
        execute(0x0C,0x01);	//turn on the chip
		execute(0x0B,0x02);	//scan two 7-segs
}

void write_7seg(unsigned char a, unsigned char b)
{
        execute(0x01, a);    // display 1
        execute(0x02, b);    // display 2
}

//===============================================
// Main program
//===============================================
int main(void)
{
	usart_init(1); //initialize USART
	sei(); //enable interrupts
	ADC_init(); //initialize AD conversion
	setup_7seg(); //initialize 7-segment displays
	timer1_init(0); // initialize timer 1
	
	while(1)
    {
    }
}

//interrupt service routine function
ISR(ADC_vect)
{
	ADCSRA = 0xBF; //clear AD complete flag
	timer1_init(1); // reset timer
	time++; //count pseudo-time

	temp_low = ADCL;
	temp_high = ADCH;
	
	int t_temp = temp_low;
	int temp_F = t_temp/200; //used to get value converted from voltage to temp
	
	int d1 = (temp_F%100)/10; //retrieve 10's place
	int d2 = temp_F%10; //retrieve 1's place
	
	write_7seg(d1,d2); // update 7-segs
	
	if(time == 5) //once count is 5, one second has passed
	{
		//Send "TEMP:"
		usart_send('T',0);
		usart_send('E',0);
		usart_send('M',0);
		usart_send('P',0);
		usart_send(':',0);
		usart_send(' ',0);
		
		usart_send(d1,1); // send digit 1
		usart_send(d2,1); // send digit 2
		usart_send('\n',0); // newline for formatting
		
		time = 0; //reset pseudo-time
	}	
}


